16 copy拷贝操作
Python中赋值操作不会复制对象,只是创建了一个新的引用。修改新变量,原变量也会跟着变——这是很多Bug的根源。copy模块就是解决这个问题的。
一、赋值 vs 拷贝
1.1 赋值只是引用
python
a = [1, 2, 3]
b = a # 赋值,b和a指向同一个对象
b.append(4)
print(a) # [1, 2, 3, 4](a也变了)
print(a is b) # True(同一个对象)1.2 浅拷贝:copy()
python
import copy
a = [1, 2, 3]
b = copy.copy(a) # 浅拷贝
b.append(4)
print(a) # [1, 2, 3](a不受影响)
print(a is b) # False(不同对象)1.3 深拷贝:deepcopy()
python
import copy
a = [[1, 2], [3, 4]]
b = copy.copy(a) # 浅拷贝
c = copy.deepcopy(a) # 深拷贝
b[0].append(999)
print(a) # [[1, 2, 999], [3, 4]](a受影响,因为浅拷贝只复制了外层)
c[0].append(888)
print(a) # [[1, 2, 999], [3, 4]](a不受影响,深拷贝递归复制了所有层)二、浅拷贝 vs 深拷贝
2.1 区别
| 操作 | 外层对象 | 内层对象 |
|---|---|---|
| 赋值 | 共享 | 共享 |
| 浅拷贝 | 新建 | 共享 |
| 深拷贝 | 新建 | 新建 |
2.2 图解
python
import copy
original = [[1, 2], [3, 4]]
# 浅拷贝
shallow = copy.copy(original)
# shallow[0] 和 original[0] 是同一个对象
# 深拷贝
deep = copy.deepcopy(original)
# deep[0] 和 original[0] 是不同对象三、哪些操作是浅拷贝
3.1 列表的浅拷贝方式
python
a = [1, 2, 3]
# 以下都是浅拷贝
b = a.copy()
b = a[:]
b = list(a)
b = copy.copy(a)3.2 字典的浅拷贝方式
python
d = {"a": 1, "b": [2, 3]}
# 以下都是浅拷贝
d2 = d.copy()
d2 = dict(d)
d2 = copy.copy(d)3.3 集合的浅拷贝方式
python
s = {1, 2, 3}
s2 = s.copy()
s2 = copy.copy(s)四、深拷贝的使用场景
4.1 嵌套可变对象
python
import copy
# 配置模板
config_template = {
"database": {"host": "localhost", "port": 5432},
"features": ["auth", "logging"]
}
# 创建独立的配置副本
config1 = copy.deepcopy(config_template)
config2 = copy.deepcopy(config_template)
config1["database"]["host"] = "192.168.1.100"
config2["features"].append("cache")
# 原模板不受影响
print(config_template)
# {'database': {'host': 'localhost', 'port': 5432}, 'features': ['auth', 'logging']}4.2 函数参数保护
python
import copy
def process_data(data):
# 深拷贝,避免修改原数据
data = copy.deepcopy(data)
data["processed"] = True
return data
original = {"name": "大志", "scores": [90, 85, 92]}
result = process_data(original)
print(original) # {'name': '大志', 'scores': [90, 85, 92]}
print(result) # {'name': '大志', 'scores': [90, 85, 92], 'processed': True}4.3 备份状态
python
import copy
class GameState:
def __init__(self):
self.position = [0, 0]
self.inventory = []
self.health = 100
def save(self):
return copy.deepcopy(self)
def restore(self, state):
self.__dict__.update(state.__dict__)
game = GameState()
game.inventory.append("sword")
# 保存状态
saved = game.save()
game.inventory.append("shield")
game.health = 50
# 恢复状态
game.restore(saved)
print(game.inventory) # ['sword']
print(game.health) # 100五、自定义拷贝行为
5.1 copy__和__deepcopy
python
import copy
class MyObject:
def __init__(self, data, cache):
self.data = data
self.cache = cache # 缓存不需要拷贝
def __copy__(self):
# 浅拷贝:只拷贝data,cache共享
new = self.__class__.__new__(self.__class__)
new.data = self.data
new.cache = self.cache
return new
def __deepcopy__(self, memo):
# 深拷贝:data递归拷贝,cache共享
new = self.__class__.__new__(self.__class__)
memo[id(self)] = new
new.data = copy.deepcopy(self.data, memo)
new.cache = self.cache # 缓存共享
return new5.2 不可拷贝的对象
python
import copy
# 某些对象不能拷贝
import threading
lock = threading.Lock()
try:
copy.deepcopy(lock)
except Exception as e:
print(f"无法拷贝: {e}")六、replace()函数(3.13+)
python
import copy
class Config:
def __init__(self, host, port):
self.host = host
self.port = port
def __replace__(self, **changes):
new = self.__class__(self.host, self.port)
new.__dict__.update(changes)
return new
config = Config("localhost", 8080)
new_config = copy.replace(config, port=9090)
print(config.host, config.port) # localhost 8080
print(new_config.host, new_config.port) # localhost 9090七、性能考虑
7.1 深拷贝的开销
python
import copy
import time
data = {"items": list(range(10000))}
# 浅拷贝快
start = time.perf_counter()
for _ in range(1000):
copy.copy(data)
print(f"浅拷贝: {time.perf_counter() - start:.4f}秒")
# 深拷贝慢
start = time.perf_counter()
for _ in range(1000):
copy.deepcopy(data)
print(f"深拷贝: {time.perf_counter() - start:.4f}秒")深拷贝比浅拷贝慢很多,因为它要递归复制所有嵌套对象。
7.2 何时用哪种
| 场景 | 用什么 |
|---|---|
| 对象只有一层 | copy() |
| 对象有嵌套可变对象 | deepcopy() |
| 不修改副本 | 不需要拷贝 |
| 只读场景 | 浅拷贝足够 |
八、实用技巧
8.1 安全地修改函数参数
python
import copy
def update_config(config, updates):
result = copy.deepcopy(config)
result.update(updates)
return result
default = {"host": "localhost", "port": 8080}
custom = update_config(default, {"port": 9090})
print(default) # {'host': 'localhost', 'port': 8080}
print(custom) # {'host': 'localhost', 'port': 9090}8.2 实现原型模式
python
import copy
class Prototype:
def clone(self):
return copy.deepcopy(self)
class Agent(Prototype):
def __init__(self, name, config):
self.name = name
self.config = config
original = Agent("Agent-1", {"model": "gpt-5", "temp": 0.7})
clone = original.clone()
clone.name = "Agent-2"
clone.config["temp"] = 0.9
print(original.name) # Agent-1
print(original.config['temp']) # 0.7(不受影响)九、总结
copy模块就两个核心函数:
| 函数 | 用途 |
|---|---|
copy.copy() | 浅拷贝:外层新建,内层共享 |
copy.deepcopy() | 深拷贝:全部新建 |
选择原则:
- 对象只有一层可变对象 →
copy() - 对象有嵌套可变对象 →
deepcopy() - 不确定 →
deepcopy()更安全
记住:赋值不拷贝,浅拷贝只拷一层,深拷贝全拷。